package org.example.erat.service.impl;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.example.erat.composite.StatisticsComposite;
import org.example.erat.entity.ClassEntity;
import org.example.erat.entity.Course;
import org.example.erat.entity.Experiment;
import org.example.erat.entity.Student;
import org.example.erat.log.core.LoggerSingleton;
import org.example.erat.log.service.OperationLogger;
import org.example.erat.parser.FileParser;
import org.example.erat.parser.FileParserFactory;
import org.example.erat.repository.ClassRepository;
import org.example.erat.repository.CourseRepository;
import org.example.erat.repository.ExperimentRepository;
import org.example.erat.repository.StudentRepository;
import org.example.erat.service.ReportAnalysisService;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.*;

/**
 * 报告分析服务实现类
 * 负责扫描和分析实验报告文件
 * 应用了多种设计模式
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ReportAnalysisServiceImpl implements ReportAnalysisService {

    private final StudentRepository studentRepository;
    private final ClassRepository classRepository;
    private final CourseRepository courseRepository;
    private final ExperimentRepository experimentRepository;
    private final StatisticsComposite statisticsComposite;
    private final OperationLogger operationLogger;

    // 保存最近一次分析结果
    private Map<String, Object> lastAnalysisResult;

    /**
     * 分析报告目录
     * @param classId 班级ID
     * @param courseId 课程ID
     * @param directoryPath 目录路径
     * @return 分析结果
     */
    @Override
    public Map<String, Object> analyzeReports(Long classId, Long courseId, String directoryPath) {
        log.info("开始分析报告目录: {}, 班级ID: {}, 课程ID: {}", directoryPath, classId, courseId);
        LoggerSingleton.getInstance().info("开始分析报告目录: {}, 班级ID: {}, 课程ID: {}", directoryPath, classId, courseId);

        try {
            // 获取班级和课程信息
            ClassEntity classEntity = classRepository.findById(classId)
                    .orElseThrow(() -> new IllegalArgumentException("班级不存在"));

            Course course = courseRepository.findById(courseId)
                    .orElseThrow(() -> new IllegalArgumentException("课程不存在"));

            // 记录扫描开始日志
            operationLogger.logScanStart(directoryPath, classEntity.getName(), course.getName());

            // 获取班级学生列表
            List<Student> students = studentRepository.findByClassEntityId(classId);
            if (students.isEmpty()) {
                throw new IllegalArgumentException("班级中没有学生");
            }
            LoggerSingleton.getInstance().info("获取到班级 {} 的学生列表，共 {} 名学生", classEntity.getName(), students.size());
            operationLogger.logOperation("获取学生列表", String.format("班级: %s, 学生数量: %d", classEntity.getName(), students.size()));

            // 获取课程实验列表
            List<Experiment> experiments = experimentRepository.findByCourseId(courseId);
            if (experiments.isEmpty()) {
                throw new IllegalArgumentException("课程中没有实验");
            }
            LoggerSingleton.getInstance().info("获取到课程 {} 的实验列表，共 {} 个实验", course.getName(), experiments.size());
            operationLogger.logOperation("获取实验列表", String.format("课程: %s, 实验数量: %d", course.getName(), experiments.size()));

            // 扫描目录结构
            Map<String, Object> reportData = scanDirectoryStructure(directoryPath, classEntity, course, students, experiments);

            // 获取处理结果统计
            int validFileCount = (int) reportData.getOrDefault("validFileCount", 0);
            int invalidFileCount = (int) reportData.getOrDefault("invalidFileCount", 0);
            int unknownStudentCount = (int) reportData.getOrDefault("unknownStudentCount", 0);
            List<String> invalidFileNames = (List<String>) reportData.getOrDefault("invalidFileNames", new ArrayList<>());
            List<Map<String, Object>> unknownStudents = (List<Map<String, Object>>) reportData.getOrDefault("unknownStudents", new ArrayList<>());

            // 使用组合模式执行统计
            Map<String, Object> result = statisticsComposite.execute(classEntity, course, students, experiments, reportData);

            // 记录扫描完成日志
            operationLogger.logScanComplete(directoryPath,
                    validFileCount + invalidFileCount,
                    validFileCount,
                    invalidFileCount,
                    unknownStudentCount);

            // 记录分析完成日志
            operationLogger.logOperation("报告分析完成",
                    String.format("班级: %s, 课程: %s, 学生数: %d, 实验数: %d",
                            classEntity.getName(), course.getName(), students.size(), experiments.size()));

            // 添加处理结果信息
            result.put("processedCount", validFileCount);
            result.put("invalidFileCount", invalidFileCount);
            result.put("unknownStudentCount", unknownStudentCount);

            // 添加异常信息
            Map<String, Object> exceptions = new HashMap<>();
            exceptions.put("invalidFormat", invalidFileNames);
            exceptions.put("unknownStudent", unknownStudents);
            result.put("exceptions", exceptions);

            // 保存最近一次分析结果
            this.lastAnalysisResult = result;

            return result;
        } catch (Exception e) {
            LoggerSingleton.getInstance().error("报告分析失败: " + e.getMessage(), e);
            operationLogger.logOperation("报告分析失败", e.getMessage());
            throw e;
        }
    }

    /**
     * 扫描目录结构
     * @param directoryPath 根目录路径
     * @param classEntity 班级
     * @param course 课程
     * @param students 学生列表
     * @param experiments 实验列表
     * @return 扫描结果
     */
    private Map<String, Object> scanDirectoryStructure(String directoryPath, ClassEntity classEntity, Course course,
                                                      List<Student> students, List<Experiment> experiments) {
        LoggerSingleton.getInstance().info("开始扫描目录结构: {}", directoryPath);
        log.info("开始扫描目录结构: {}", directoryPath);

        File rootDir = new File(directoryPath);
        if (!rootDir.exists() || !rootDir.isDirectory()) {
            String errorMsg = "目录不存在或不是目录: " + directoryPath;
            LoggerSingleton.getInstance().error(errorMsg);
            log.error(errorMsg);
            throw new IllegalArgumentException(errorMsg);
        }

        // 打印目录内容，便于调试
        File[] rootFiles = rootDir.listFiles();
        if (rootFiles == null || rootFiles.length == 0) {
            String warnMsg = "目录为空: " + directoryPath;
            LoggerSingleton.getInstance().warn(warnMsg);
            log.warn(warnMsg);
            throw new IllegalArgumentException(warnMsg);
        } else {
            LoggerSingleton.getInstance().info("目录 {} 包含 {} 个文件/子目录", directoryPath, rootFiles.length);
            log.info("目录 {} 包含 {} 个文件/子目录", directoryPath, rootFiles.length);

            // 打印目录内容
            for (File file : rootFiles) {
                LoggerSingleton.getInstance().info("  - {}: {}", file.isDirectory() ? "目录" : "文件", file.getName());
                log.info("  - {}: {}", file.isDirectory() ? "目录" : "文件", file.getName());
            }

            // 检查是否包含实验报告文件
            boolean containsReportFiles = false;
            for (File file : rootFiles) {
                if (file.isFile() && isReportFile(file.getName())) {
                    containsReportFiles = true;
                    break;
                } else if (file.isDirectory()) {
                    File[] subFiles = file.listFiles();
                    if (subFiles != null) {
                        for (File subFile : subFiles) {
                            if (subFile.isFile() && isReportFile(subFile.getName())) {
                                containsReportFiles = true;
                                break;
                            }
                        }
                    }
                    if (containsReportFiles) break;
                }
            }

            if (!containsReportFiles) {
                String warnMsg = "目录中未找到实验报告文件: " + directoryPath;
                LoggerSingleton.getInstance().warn(warnMsg);
                log.warn(warnMsg);
            }
        }

        Map<String, Object> result = new HashMap<>();
        Map<String, Set<String>> submittedStudentIds = new HashMap<>();

        // 统计变量
        int totalValidFileCount = 0;
        int totalInvalidFileCount = 0;
        int totalUnknownStudentCount = 0;
        List<String> invalidFileNames = new ArrayList<>();
        List<Map<String, Object>> unknownStudents = new ArrayList<>();

        // 查找班级目录
        File classDir = findClassDirectory(rootDir, classEntity.getName());
        if (classDir == null) {
            log.warn("未找到班级目录: {}", classEntity.getName());
            LoggerSingleton.getInstance().warn("未找到班级目录: {}，将使用根目录", classEntity.getName());

            // 尝试直接在根目录查找实验报告文件
            boolean rootContainsReports = false;
            for (File file : rootFiles) {
                if (file.isFile() && isReportFile(file.getName())) {
                    rootContainsReports = true;
                    break;
                }
            }

            if (rootContainsReports) {
                LoggerSingleton.getInstance().info("根目录直接包含实验报告文件，将使用根目录");
                log.info("根目录直接包含实验报告文件，将使用根目录");
            } else {
                // 尝试查找可能包含实验报告的子目录
                for (File file : rootFiles) {
                    if (file.isDirectory()) {
                        File[] subFiles = file.listFiles();
                        if (subFiles != null) {
                            for (File subFile : subFiles) {
                                if (subFile.isFile() && isReportFile(subFile.getName())) {
                                    classDir = file;
                                    LoggerSingleton.getInstance().info("找到包含实验报告的目录: {}", file.getAbsolutePath());
                                    log.info("找到包含实验报告的目录: {}", file.getAbsolutePath());
                                    break;
                                }
                            }
                        }
                        if (classDir != null) break;
                    }
                }
            }

            // 如果仍未找到，使用根目录
            if (classDir == null) {
                classDir = rootDir;
                LoggerSingleton.getInstance().info("未找到合适的班级目录，将使用根目录: {}", rootDir.getAbsolutePath());
                log.info("未找到合适的班级目录，将使用根目录: {}", rootDir.getAbsolutePath());
            }
        } else {
            LoggerSingleton.getInstance().info("找到班级目录: {}", classDir.getAbsolutePath());
            log.info("找到班级目录: {}", classDir.getAbsolutePath());
        }

        // 遍历实验目录，收集提交信息
        for (Experiment experiment : experiments) {
            // 初始化该实验的已提交学生ID集合
            Set<String> submittedIds = new HashSet<>();
            submittedStudentIds.put(experiment.getName(), submittedIds);

            // 查找实验目录
            File experimentDir = findExperimentDirectory(classDir, experiment.getName());
            if (experimentDir != null && experimentDir.exists() && experimentDir.isDirectory()) {
                LoggerSingleton.getInstance().info("找到实验目录: {}", experimentDir.getAbsolutePath());
                log.info("找到实验目录: {}", experimentDir.getAbsolutePath());

                // 分析实验报告
                Map<String, Object> experimentResult = analyzeExperimentReports(experimentDir, experiment, students, submittedIds);

                // 累加统计数据
                totalValidFileCount += (int) experimentResult.getOrDefault("validFileCount", 0);
                totalInvalidFileCount += (int) experimentResult.getOrDefault("invalidFileCount", 0);
                totalUnknownStudentCount += (int) experimentResult.getOrDefault("unknownStudentCount", 0);

                @SuppressWarnings("unchecked")
                List<String> invalidNames = (List<String>) experimentResult.getOrDefault("invalidFileNames", new ArrayList<>());
                invalidFileNames.addAll(invalidNames);

                @SuppressWarnings("unchecked")
                List<Map<String, Object>> unknownStudentsList = (List<Map<String, Object>>) experimentResult.getOrDefault("unknownStudents", new ArrayList<>());
                unknownStudents.addAll(unknownStudentsList);
            } else {
                // 如果没有找到实验目录，尝试直接在班级目录中查找该实验的报告文件
                log.info("未找到实验目录: {}，尝试直接在班级目录中查找报告文件", experiment.getName());
                LoggerSingleton.getInstance().info("未找到实验目录: {}，尝试直接在班级目录中查找报告文件", experiment.getName());

                File[] classFiles = classDir.listFiles();
                if (classFiles != null) {
                    List<File> experimentFiles = new ArrayList<>();

                    // 查找与实验名称匹配的文件
                    for (File file : classFiles) {
                        if (file.isFile() && isReportFile(file.getName())) {
                            String fileName = file.getName().toLowerCase();
                            String experimentName = experiment.getName().toLowerCase();

                            // 检查文件名是否包含实验名称
                            if (fileName.contains(experimentName) ||
                                (experimentName.matches("实验\\d+") &&
                                 fileName.matches(".*实验0*" + experimentName.replaceAll("实验", "") + ".*"))) {
                                experimentFiles.add(file);
                            }
                        }
                    }

                    if (!experimentFiles.isEmpty()) {
                        LoggerSingleton.getInstance().info("在班级目录中找到 {} 个与实验 {} 相关的报告文件",
                                experimentFiles.size(), experiment.getName());
                        log.info("在班级目录中找到 {} 个与实验 {} 相关的报告文件",
                                experimentFiles.size(), experiment.getName());

                        // 创建临时目录用于分析
                        File tempDir = new File(classDir, "temp_" + experiment.getName());
                        tempDir.mkdir();

                        // 分析这些文件
                        Map<String, Object> experimentResult = analyzeExperimentFiles(experimentFiles, experiment, students, submittedIds);

                        // 累加统计数据
                        totalValidFileCount += (int) experimentResult.getOrDefault("validFileCount", 0);
                        totalInvalidFileCount += (int) experimentResult.getOrDefault("invalidFileCount", 0);
                        totalUnknownStudentCount += (int) experimentResult.getOrDefault("unknownStudentCount", 0);

                        @SuppressWarnings("unchecked")
                        List<String> invalidNames = (List<String>) experimentResult.getOrDefault("invalidFileNames", new ArrayList<>());
                        invalidFileNames.addAll(invalidNames);

                        @SuppressWarnings("unchecked")
                        List<Map<String, Object>> unknownStudentsList = (List<Map<String, Object>>) experimentResult.getOrDefault("unknownStudents", new ArrayList<>());
                        unknownStudents.addAll(unknownStudentsList);
                    } else {
                        log.warn("未找到实验目录或相关报告文件: {}", experiment.getName());
                        LoggerSingleton.getInstance().warn("未找到实验目录或相关报告文件: {}", experiment.getName());
                    }
                } else {
                    log.warn("未找到实验目录: {}", experiment.getName());
                    LoggerSingleton.getInstance().warn("未找到实验目录: {}", experiment.getName());
                }
            }
        }

        // 将提交信息添加到结果中
        result.put("submittedStudentIds", submittedStudentIds);

        // 记录扫描结果
        int totalFiles = 0;
        for (Set<String> ids : submittedStudentIds.values()) {
            totalFiles += ids.size();
        }
        LoggerSingleton.getInstance().info("扫描完成，共找到 {} 个实验报告文件", totalFiles);

        // 添加统计信息
        result.put("validFileCount", totalValidFileCount);
        result.put("invalidFileCount", totalInvalidFileCount);
        result.put("unknownStudentCount", totalUnknownStudentCount);
        result.put("invalidFileNames", invalidFileNames);
        result.put("unknownStudents", unknownStudents);

        // 记录异常信息
        if (totalInvalidFileCount > 0) {
            LoggerSingleton.getInstance().warn("发现 {} 个文件名不合规", totalInvalidFileCount);
        }
        if (totalUnknownStudentCount > 0) {
            LoggerSingleton.getInstance().warn("发现 {} 个学生不在名单中", totalUnknownStudentCount);
        }

        return result;
    }

    /**
     * 查找班级目录
     * @param rootDir 根目录
     * @param className 班级名称
     * @return 班级目录
     */
    private File findClassDirectory(File rootDir, String className) {
        LoggerSingleton.getInstance().info("查找班级目录: {}", className);

        File[] files = rootDir.listFiles();
        if (files == null) {
            LoggerSingleton.getInstance().warn("根目录 {} 无法列出文件", rootDir.getAbsolutePath());
            return null;
        }

        LoggerSingleton.getInstance().info("根目录 {} 包含 {} 个文件/子目录", rootDir.getAbsolutePath(), files.length);

        // 首先尝试精确匹配
        for (File file : files) {
            if (file.isDirectory() && file.getName().equals(className)) {
                LoggerSingleton.getInstance().info("找到精确匹配的班级目录: {}", file.getAbsolutePath());
                return file;
            }
        }

        // 然后尝试包含匹配
        for (File file : files) {
            if (file.isDirectory() && file.getName().contains(className)) {
                LoggerSingleton.getInstance().info("找到包含匹配的班级目录: {}", file.getAbsolutePath());
                return file;
            }
        }

        // 尝试忽略大小写匹配
        for (File file : files) {
            if (file.isDirectory() && file.getName().toLowerCase().contains(className.toLowerCase())) {
                LoggerSingleton.getInstance().info("找到忽略大小写匹配的班级目录: {}", file.getAbsolutePath());
                return file;
            }
        }

        LoggerSingleton.getInstance().warn("未找到班级目录: {}", className);
        return null;
    }

    /**
     * 查找实验目录
     * @param classDir 班级目录
     * @param experimentName 实验名称
     * @return 实验目录
     */
    private File findExperimentDirectory(File classDir, String experimentName) {
        LoggerSingleton.getInstance().info("查找实验目录: {}", experimentName);

        File[] files = classDir.listFiles();
        if (files == null) {
            LoggerSingleton.getInstance().warn("班级目录 {} 无法列出文件", classDir.getAbsolutePath());
            return null;
        }

        LoggerSingleton.getInstance().info("班级目录 {} 包含 {} 个文件/子目录", classDir.getAbsolutePath(), files.length);

        // 首先尝试精确匹配
        for (File file : files) {
            if (file.isDirectory() && file.getName().equals(experimentName)) {
                LoggerSingleton.getInstance().info("找到精确匹配的实验目录: {}", file.getAbsolutePath());
                return file;
            }
        }

        // 然后尝试包含匹配
        for (File file : files) {
            if (file.isDirectory() && file.getName().contains(experimentName)) {
                LoggerSingleton.getInstance().info("找到包含匹配的实验目录: {}", file.getAbsolutePath());
                return file;
            }
        }

        // 尝试忽略大小写匹配
        for (File file : files) {
            if (file.isDirectory() && file.getName().toLowerCase().contains(experimentName.toLowerCase())) {
                LoggerSingleton.getInstance().info("找到忽略大小写匹配的实验目录: {}", file.getAbsolutePath());
                return file;
            }
        }

        // 尝试数字匹配（如"实验1"匹配"实验01"）
        if (experimentName.matches("实验\\d+")) {
            String experimentNumber = experimentName.replaceAll("实验", "");
            int number = Integer.parseInt(experimentNumber);

            for (File file : files) {
                if (file.isDirectory()) {
                    String fileName = file.getName();
                    if (fileName.matches("实验0*" + number) || fileName.matches("实验0*" + number + ".*")) {
                        LoggerSingleton.getInstance().info("找到数字匹配的实验目录: {}", file.getAbsolutePath());
                        return file;
                    }
                }
            }
        }

        LoggerSingleton.getInstance().warn("未找到实验目录: {}", experimentName);
        return null;
    }

    /**
     * 判断文件是否为实验报告文件
     * @param fileName 文件名
     * @return 是否为实验报告文件
     */
    private boolean isReportFile(String fileName) {
        // 检查文件扩展名
        String lowerFileName = fileName.toLowerCase();
        if (lowerFileName.endsWith(".xlsx") || lowerFileName.endsWith(".xls") ||
            lowerFileName.endsWith(".csv") || lowerFileName.endsWith(".doc") ||
            lowerFileName.endsWith(".docx")) {
            // 检查文件名格式是否符合 "实验X_学号_姓名.扩展名" 的模式
            String nameWithoutExt = lowerFileName.substring(0, lowerFileName.lastIndexOf('.'));
            String[] parts = nameWithoutExt.split("_");
            return parts.length >= 3 && parts[0].startsWith("实验");
        }
        return false;
    }

    /**
     * 分析实验报告文件列表
     * @param files 文件列表
     * @param experiment 实验
     * @param students 学生列表
     * @param submittedStudentIds 已提交学生ID集合
     * @return 分析结果
     */
    private Map<String, Object> analyzeExperimentFiles(List<File> files, Experiment experiment, List<Student> students,
                                                     Set<String> submittedStudentIds) {
        ClassEntity classEntity = students.isEmpty() ? null : students.get(0).getClassEntity();

        // 统计变量
        int fileCount = 0;
        int validFileCount = 0;
        int invalidFileCount = 0;
        int unknownStudentCount = 0;
        List<String> invalidFileNames = new ArrayList<>();
        List<Map<String, Object>> unknownStudents = new ArrayList<>();

        for (File file : files) {
            if (file.isFile()) {
                fileCount++;
                String fileName = file.getName();
                String fileExtension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();

                // 检查是否是支持的文件类型
                if (!fileExtension.equals("xlsx") && !fileExtension.equals("xls") &&
                    !fileExtension.equals("csv") && !fileExtension.equals("doc") &&
                    !fileExtension.equals("docx")) {
                    LoggerSingleton.getInstance().warn("不支持的文件类型: {}，仅支持Excel、Word和CSV格式", fileExtension);
                    operationLogger.logUnsupportedFileType(fileName, fileExtension);
                    continue;
                }

                try {
                    // 使用工厂模式获取解析器
                    FileParser parser = FileParserFactory.getParser(fileExtension);

                    // 验证文件名
                    if (!parser.validateFileName(fileName)) {
                        LoggerSingleton.getInstance().warn("文件名格式不正确: {}", fileName);
                        operationLogger.logInvalidFileName(fileName, experiment.getName());
                        // 记录更详细的文件名格式错误信息
                        operationLogger.logFileNameFormatError(fileName, "实验名_学号_姓名.doc|docx|xlsx|xls|csv");
                        invalidFileCount++;
                        invalidFileNames.add(fileName);
                        continue;
                    }

                    // 从文件名中提取信息
                    Map<String, String> fileNameInfo = parser.extractInfoFromFileName(fileName);
                    String studentId = fileNameInfo.get("studentId");
                    String studentName = fileNameInfo.get("studentName");

                    // 检查学生是否在班级中
                    Optional<Student> studentOpt = students.stream()
                            .filter(s -> s.getStudentId().equals(studentId))
                            .findFirst();

                    if (studentOpt.isPresent()) {
                        Student student = studentOpt.get();
                        submittedStudentIds.add(studentId);
                        validFileCount++;

                        // 记录文件信息到数据库或其他存储
                        log.info("找到学生 {} 的实验 {} 报告: {}", student.getName(), experiment.getName(), fileName);
                        LoggerSingleton.getInstance().info("找到学生 {} 的实验 {} 报告: {}",
                                student.getName(), experiment.getName(), fileName);
                    } else {
                        unknownStudentCount++;
                        LoggerSingleton.getInstance().warn("文件 {} 对应的学生不在班级名单中", fileName);
                        operationLogger.logUnknownStudent(fileName, studentId, studentName, experiment.getName());

                        // 记录更详细的学生不在名单中的信息
                        String className = "未知班级";
                        if (!students.isEmpty() && students.get(0).getClassEntity() != null) {
                            className = students.get(0).getClassEntity().getName();
                        }
                        operationLogger.logStudentNotInClass(studentId, studentName, className);

                        // 记录未知学生信息
                        Map<String, Object> unknownStudent = new HashMap<>();
                        unknownStudent.put("fileName", fileName);
                        unknownStudent.put("studentId", studentId);
                        unknownStudent.put("studentName", studentName);
                        unknownStudent.put("experimentName", experiment.getName());
                        unknownStudents.add(unknownStudent);
                    }
                } catch (Exception e) {
                    LoggerSingleton.getInstance().error("解析文件 {} 时发生错误: {}", fileName, e.getMessage());
                    operationLogger.logFileParseError(fileName, e.getMessage());
                }
            }
        }

        LoggerSingleton.getInstance().info("实验 {} 报告分析完成，共 {} 个文件，有效文件 {} 个，未知学生 {} 个",
                experiment.getName(), fileCount, validFileCount, unknownStudentCount);

        // 记录实验报告分析结果
        operationLogger.logReportAnalysis(experiment.getName(), fileCount, validFileCount, classEntity.getName());

        // 返回统计结果
        Map<String, Object> result = new HashMap<>();
        result.put("validFileCount", validFileCount);
        result.put("invalidFileCount", invalidFileCount);
        result.put("unknownStudentCount", unknownStudentCount);
        result.put("invalidFileNames", invalidFileNames);
        result.put("unknownStudents", unknownStudents);
        return result;
    }

    /**
     * 获取最近一次分析结果
     * @return 分析结果
     */
    @Override
    public Map<String, Object> getLastAnalysisResult() {
        return lastAnalysisResult;
    }

    /**
     * 分析实验报告
     * @param experimentDir 实验目录
     * @param experiment 实验
     * @param students 学生列表
     * @param submittedStudentIds 已提交学生ID集合
     */
    private Map<String, Object> analyzeExperimentReports(File experimentDir, Experiment experiment, List<Student> students,
                                         Set<String> submittedStudentIds) {
        ClassEntity classEntity = students.isEmpty() ? null : students.get(0).getClassEntity();
        File[] files = experimentDir.listFiles();
        if (files == null) {
            LoggerSingleton.getInstance().warn("实验目录为空: {}", experimentDir.getAbsolutePath());
            Map<String, Object> emptyResult = new HashMap<>();
            emptyResult.put("validFileCount", 0);
            emptyResult.put("invalidFileCount", 0);
            emptyResult.put("unknownStudentCount", 0);
            emptyResult.put("invalidFileNames", new ArrayList<String>());
            emptyResult.put("unknownStudents", new ArrayList<Map<String, Object>>());
            return emptyResult;
        }

        // 统计变量
        int fileCount = 0;
        int validFileCount = 0;
        int invalidFileCount = 0;
        int unknownStudentCount = 0;
        List<String> invalidFileNames = new ArrayList<>();
        List<Map<String, Object>> unknownStudents = new ArrayList<>();

        for (File file : files) {
            if (file.isFile()) {
                fileCount++;
                String fileName = file.getName();
                String fileExtension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();

                // 检查是否是支持的文件类型
                if (!fileExtension.equals("xlsx") && !fileExtension.equals("xls") &&
                    !fileExtension.equals("csv") && !fileExtension.equals("doc") &&
                    !fileExtension.equals("docx")) {
                    LoggerSingleton.getInstance().warn("不支持的文件类型: {}，仅支持Excel、Word和CSV格式", fileExtension);
                    operationLogger.logUnsupportedFileType(fileName, fileExtension);
                    continue;
                }

                try {
                    // 使用工厂模式获取解析器
                    FileParser parser = FileParserFactory.getParser(fileExtension);

                    // 验证文件名
                    if (!parser.validateFileName(fileName)) {
                        LoggerSingleton.getInstance().warn("文件名格式不正确: {}", fileName);
                        operationLogger.logInvalidFileName(fileName, experiment.getName());
                        // 记录更详细的文件名格式错误信息
                        operationLogger.logFileNameFormatError(fileName, "实验名_学号_姓名.doc|docx|xlsx|xls|csv");
                        invalidFileCount++;
                        invalidFileNames.add(fileName);
                        continue;
                    }

                    // 从文件名中提取信息
                    Map<String, String> fileNameInfo = parser.extractInfoFromFileName(fileName);
                    String studentId = fileNameInfo.get("studentId");
                    String studentName = fileNameInfo.get("studentName");

                    // 检查学生是否在班级中
                    Optional<Student> studentOpt = students.stream()
                            .filter(s -> s.getStudentId().equals(studentId))
                            .findFirst();

                    if (studentOpt.isPresent()) {
                        Student student = studentOpt.get();
                        submittedStudentIds.add(studentId);
                        validFileCount++;

                        // 记录文件信息到数据库或其他存储
                        log.info("找到学生 {} 的实验 {} 报告: {}", student.getName(), experiment.getName(), fileName);
                        LoggerSingleton.getInstance().info("找到学生 {} 的实验 {} 报告: {}",
                                student.getName(), experiment.getName(), fileName);
                    } else {
                        unknownStudentCount++;
                        LoggerSingleton.getInstance().warn("文件 {} 对应的学生不在班级名单中", fileName);
                        operationLogger.logUnknownStudent(fileName, studentId, studentName, experiment.getName());

                        // 记录更详细的学生不在名单中的信息
                        String className = "未知班级";
                        if (!students.isEmpty() && students.get(0).getClassEntity() != null) {
                            className = students.get(0).getClassEntity().getName();
                        }
                        operationLogger.logStudentNotInClass(studentId, studentName, className);

                        // 记录未知学生信息
                        Map<String, Object> unknownStudent = new HashMap<>();
                        unknownStudent.put("fileName", fileName);
                        unknownStudent.put("studentId", studentId);
                        unknownStudent.put("studentName", studentName);
                        unknownStudent.put("experimentName", experiment.getName());
                        unknownStudents.add(unknownStudent);
                    }
                } catch (Exception e) {
                    LoggerSingleton.getInstance().error("解析文件 {} 时发生错误: {}", fileName, e.getMessage());
                    operationLogger.logFileParseError(fileName, e.getMessage());
                }
            }
        }

        LoggerSingleton.getInstance().info("实验 {} 报告分析完成，共 {} 个文件，有效文件 {} 个，未知学生 {} 个",
                experiment.getName(), fileCount, validFileCount, unknownStudentCount);

        // 记录实验报告分析结果
        operationLogger.logReportAnalysis(experiment.getName(), fileCount, validFileCount, classEntity.getName());

        // 返回统计结果
        Map<String, Object> result = new HashMap<>();
        result.put("validFileCount", validFileCount);
        result.put("invalidFileCount", invalidFileCount);
        result.put("unknownStudentCount", unknownStudentCount);
        result.put("invalidFileNames", invalidFileNames);
        result.put("unknownStudents", unknownStudents);
        return result;
    }
}
